package com.bluesky.plum.uimodels.standard;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.springframework.context.ApplicationContext;

import com.bluesky.plum.domain.northwind.Employee;
import com.bluesky.plum.domain.northwind.EmployeeRepository;
import com.bluesky.plum.domain.repository.PersonRepository;
import com.bluesky.plum.domain.repository.impl.HibernateRepository;
import com.bluesky.plum.domain.service.HRService;
import com.bluesky.plum.domain.tool.Calculator;
import com.bluesky.plum.domain.tool.CalculatorImpl;
import com.bluesky.plum.richdomain.RichDomainField;
import com.bluesky.plum.richdomain.RichDomainFields;
import com.bluesky.plum.richdomain.RichDomainMethod;
import com.bluesky.plum.richdomain.annotation.OUMMethod;
import com.bluesky.plum.uimodels.render.html.HTMLUIComponentBuilder;
import com.bluesky.plum.uimodels.render.swing.SwingUIComponentBuilder;
import com.bluesky.plum.uimodels.standard.components.EventListener;
import com.bluesky.plum.uimodels.standard.components.containers.Panel;
import com.bluesky.plum.uimodels.standard.components.containers.form.Form;
import com.bluesky.plum.uimodels.standard.components.containers.window.MainWindow;
import com.bluesky.plum.uimodels.standard.components.menu.Menu;
import com.bluesky.plum.uimodels.standard.components.menu.MenuBar;
import com.bluesky.plum.uimodels.standard.components.menu.MenuItem;
import com.bluesky.plum.util.SpringFrameworkUtil;

public class StandardApplicationUIBuilder implements ApplicationUIBuilder {
	/**
	 * business object class, and its pair of instance. Here separate the class
	 * and the instance because the declaration and the implementation maybe
	 * separated. such as Spring IOC delegation, Interface.
	 * 
	 */

	protected UIComponentBuilder uiComponentBuilder;

	public StandardApplicationUIBuilder(UIComponentBuilder uiComponentBuilder) {
		this.uiComponentBuilder = uiComponentBuilder;
	}

	@Override
	public MainWindow createUI(BusinessObject[] businessObjects) {

		// reflect the business objects, show menu group and items.
		// if a menu item is clicked, then show the form which contains the
		// parameters.

		final MainWindow appWindow = (MainWindow) uiComponentBuilder
				.createNonFieldComponent(StandardUIComponentType.MainWindow);
		appWindow.setTitle("powered by OUM project");

		Panel panel1 = (Panel) uiComponentBuilder
				.createNonFieldComponent(StandardUIComponentType.Panel);
		// box1.setDirection(Box.Direction.Vertical);
		appWindow.setContentPanel(panel1);

		appWindow.setHeadPanel((Panel) uiComponentBuilder
				.createNonFieldComponent(StandardUIComponentType.Panel));

		final MenuBar menuBar = (MenuBar) uiComponentBuilder
				.createNonFieldComponent(StandardUIComponentType.MenuBar);

		// create menus
		for (final BusinessObject bo : businessObjects) {
			Menu menu = (Menu) uiComponentBuilder
					.createNonFieldComponent(StandardUIComponentType.Menu);

			
			menu.setCaption(bo.toString());

			Method[] methods = bo.getClazz().getMethods();
			// create menu item for method
			for (final Method m : methods) {
				if (m.isAnnotationPresent(OUMMethod.class)) {
					final RichDomainMethod rdm = new RichDomainMethod(
							bo.getInstance(), m, bo.getGenericTypeMap());

					final MenuItem mi = (MenuItem) uiComponentBuilder
							.createNonFieldComponent(StandardUIComponentType.MenuItem);

					if (rdm.caption == null || rdm.caption.isEmpty())
						mi.setCaption(m.getName());
					else
						mi.setCaption(rdm.caption);

					// define menu item click handler code. it show parameter
					// list and 2 buttons.
					mi.setClickListener(new EventListener() {
						@Override
						public void process() {

							RichDomainFields rdfs = RichDomainFields
									.createFromMethod(rdm);

							final UIComponent[] uics = uiComponentBuilder
									.createComponents(rdfs.getFields()
											.getList().toArray(
													new RichDomainField[] {}));
							//
							// final Panel contentPanel = appWindow
							// .getContentPanel();
							// contentPanel.clear();

							Form form = uiComponentBuilder.createForm(rdm);
							Panel p = (Panel) uiComponentBuilder
									.createNonFieldComponent(StandardUIComponentType.Panel);
							p.addChildComponent(form);
							appWindow.setContentPanel(p);
							// contentPanel.addChildComponent(form);

							appWindow.getRootWindow().pack();
						}
					});

					menu.addMenuItem(mi);
				}
			}

			menuBar.addMenu(menu);

		}

		MainWindow mw = (MainWindow) appWindow.getRootWindow();
		mw.setMenuBar(menuBar);

		appWindow.setVisible(true);

		return appWindow;
	}

	protected Map<Class, Object> createSampleBOs() {
		Map<Class, Object> businessObjects = new HashMap<Class, Object>();

		// 3 business service objects
		PersonRepository repo = new PersonRepository();
		businessObjects.put(PersonRepository.class, repo);

		Calculator calc = new CalculatorImpl();
		businessObjects.put(Calculator.class, calc);

		HRService hrsvc = new HRService();
		businessObjects.put(HRService.class, hrsvc);

		EmployeeRepository employeeRepo = new EmployeeRepository();
		businessObjects.put(EmployeeRepository.class, employeeRepo);

//		HibernateRepository<Employee> hibEmployeeRepo = new HibernateRepository(
//				Employee.class);
//		businessObjects.put(EmployeeRepository.class, employeeRepo);

		return businessObjects;
	}

	public static MainWindow createSampleUIOfSwing(BusinessObject[] businessObjects) {
		StandardApplicationUIBuilder swing = new StandardApplicationUIBuilder(
				new SwingUIComponentBuilder());
		// Map<Class, Object> bos = swing.createSampleBOs();
		MainWindow appWindow = swing.createUI(businessObjects);

		return appWindow;
	}

	public static MainWindow createSampleUIOfHtml(BusinessObject[] businessObjects) {
		StandardApplicationUIBuilder builder = new StandardApplicationUIBuilder(
				new HTMLUIComponentBuilder());
		// Map<Class, Object> bos = builder.createSampleBOs();
		MainWindow appWindow = builder.createUI(businessObjects);

		return appWindow;
	}

	public static void main(String[] args) {

		// StandardApplicationUIBuilder standard = new
		// StandardApplicationUIBuilder(
		// new StandardUIComponentBuilder());
		//
		// UIComponent ui1 = standard.createUI(bos).getWindow();
		//
		// StandardApplicationUIBuilder html = new HTMLApplicationUIBuilder(
		// new HTMLUIComponentBuilder());
		// UIComponent ui2 = html.createUI(bos);
		ApplicationContext ctx = SpringFrameworkUtil.getApplicationContext();
		SpringFrameworkUtil.registerRepositories(ctx);
		MainWindow appWindow = createSampleUIOfSwing(SpringFrameworkUtil
				.getBusinessObjectPairs(ctx));

		appWindow.getRootWindow().setVisible(true);

		// frame.setVisible(true);

	}

}
